#include "MutaPacketListener.h"

#include <QString>
#include "osc/OscReceivedElements.h"
#include "osc/OscPacketListener.h"
#include "ip/UdpSocket.h"
#include "stdio.h"
#include <QDebug>
#include "Global.h"

MutaPacketListener::MutaPacketListener() {
}


void MutaPacketListener::ProcessMessage( const osc::ReceivedMessage& m,
                                const IpEndpointName& remoteEndpoint )
    {
        try{
            // example of parsing single messages. osc::OsckPacketListener
            // handles the bundle traversal.
            if( strcmp( m.AddressPattern(), "/test1" ) == 0 ){
                // example #1 -- argument stream interface
                osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
                bool a1;
                osc::int32 a2;
                float a3;
                const char *a4;
                args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage;

                qDebug() << "received '/test1' message with arguments: "
                    << a1 << " " << a2 << " " << a3 << " " << a4;

            } else if( strcmp( m.AddressPattern(), "/test2" ) == 0 ){
                // example #2 -- argument iterator interface, supports
                // reflection for overloaded messages (eg you can call
                // (*arg)->IsBool() to check if a bool was passed etc).
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                bool a1 = (arg++)->AsBool();
                int a2 = (arg++)->AsInt32();
                float a3 = (arg++)->AsFloat();
                const char *a4 = (arg++)->AsString();
                if( arg != m.ArgumentsEnd() )
                    throw osc::ExcessArgumentException();

                qDebug() << "received '/test2' message with arguments: "
                    << a1 << " " << a2 << " " << a3 << " " << a4;
            } else if( strcmp( m.AddressPattern(), "/userName" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                Muta::userName = (arg++)->AsString();
                qDebug() <<"userName is: " << Muta::userName;
                emit loggedIn();
            } else if( strcmp( m.AddressPattern(), "/addPeer" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                QString user((arg++)->AsString());
                qDebug() <<"Added peer: " << user;
                //emit userAdded(user);
            } else if( strcmp( m.AddressPattern(), "/removePeer" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                QString user((arg++)->AsString());
                qDebug() <<"Removed peer: " << user;
                //emit userRemoved(user);
            } else if( strcmp( m.AddressPattern(), "/addSyncObject" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                QString objectID = (arg++)->AsString();
                QString type = (arg++)->AsString();
                QString subType = (arg++)->AsString();
                QString owner = (arg++)->AsString();

                int count = QString(objectID).toInt();
                if(Muta::objectCount < count) {
                    Muta::objectCount = count +1;
                }

                if(type.compare("e") ==0) {

                    float x = (arg++)->AsFloat();
                    float y = (arg++)->AsFloat();
                    int layer = (arg++)->AsInt32();
                    float length =  (arg++)->AsFloat();
                    qDebug() << "Added SyncObject: "
                            << "object ID:" << objectID
                            << "type:" << type
                            << "subType:" <<subType
                            << "owner:" << owner
                            << "x:" << x
                            << "y:"<< y
                            << "layer:" <<layer
                            << "length:" << length;
                    emit addMutaEvent(objectID,owner,x,y,layer,length);
                } else if((type.compare("l")==0) || (type.compare("c")==0)) {
                    float x = (arg++)->AsFloat();
                    float y = (arg++)->AsFloat();
                    int layer = (arg++)->AsInt32();
                    QString controlPoints = QString((arg++)->AsString());
                    qDebug() << "Added SyncObject: "
                            << "object ID:" << objectID
                            << "type:" << type
                            << "subType:" <<subType
                            << "owner:" << owner
                            << "x:" << x
                            << "y:"<< y
                            << "layer:" <<layer
                            << "controlPoints" << controlPoints;
                    emit addMutaLine(objectID,type,owner,x,y,layer,controlPoints);
                } else if(type.compare("uc")==0) {
                    qDebug() << "Added SyncObject: "
                            << "object ID:" << objectID
                            << "type:" << type
                            << "subType:" <<subType
                            << "owner:" << owner;
                    emit addUserCursor(objectID,owner);
                }
            } else if( strcmp( m.AddressPattern(), "/removeSyncObject" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                QString objectID = (arg++)->AsString();
                QString type = (arg++)->AsString();
                QString subType = (arg++)->AsString();
                qDebug() << "Removed SyncObject: " << objectID << type << subType;
                emit removeMutaObject(objectID);
            } else if( strcmp( m.AddressPattern(), "/setSyncArg" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                QString type;
                int numArgs = m.ArgumentCount();

                for(int i = 0; i < numArgs; i++){
                    if(i == (numArgs-1)){
                        type = QString((arg++)->AsString());
                    } else {
                        arg++;
                        //type = QString((arg++)->AsString());
                    }
                }
                arg = m.ArgumentsBegin();
                QString objectID = (arg++)->AsString();
                if(type.compare("e")==0) {
                    int argNum = (arg++)->AsInt32();
                    //qDebug() << "setSyncArg, argNum:" << argNum;
                    switch(argNum) {
                        case 0:
                            //owner
                            break;
                        case 1:
                            //x
                            emit setMutaX(objectID,(arg++)->AsFloat());
                            break;
                        case 2:
                            //y
                            emit setMutaY(objectID,(arg++)->AsFloat());
                            break;
                        case 3:
                            //layer
                            break;
                        case 4:
                            //length
                            break;
                    }
                } else if(type.compare("l")==0) {
                    int argNum = (arg++)->AsInt32();
                    //qDebug() << "setSyncArg, argNum:" << argNum;
                    switch(argNum) {
                        case 0:
                            //owner
                            break;
                        case 1:
                            //x
                            emit setMutaX(objectID,(arg++)->AsFloat());
                            break;
                        case 2:
                            //y
                            emit setMutaY(objectID,(arg++)->AsFloat());
                            break;
                        case 3:
                            //layer
                            break;
                        case 4:
                            //controlPoints/controlPoints
                            emit setControlPoints(objectID, QString((arg++)->AsString()));
                            break;
                    }
                } else if(type.compare("uc")==0) {
                    int argNum = (arg++)->AsInt32();
                    //qDebug() << "setSyncArg, argNum:" << argNum;
                    switch(argNum) {
                        case 0:
                            //owner
                            break;
                        case 1:
                            //x
                            emit setMutaX(objectID,(arg++)->AsFloat());
                            break;
                        case 2:
                            //y
                            emit setMutaY(objectID,(arg++)->AsFloat());
                            break;
                    }
                }
            } else if( strcmp( m.AddressPattern(), "/startAllNotes" ) == 0 ){
                emit startAllNotes();
                qDebug() << "start all notes";
            }
    } catch( osc::Exception& e ){
        // any parsing errors such as unexpected argument types, or
        // missing arguments get thrown as exceptions.
        qDebug() << "error while parsing message: "
            << m.AddressPattern() << ": " << e.what();
    }
}
